home *** CD-ROM | disk | FTP | other *** search
/ AP Professional Graphics CD-ROM Library / AP Professional Graphics CD-ROM Library.iso / pc / unix / appendix / gemsi / polyscan / polyscan.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-26  |  4.7 KB  |  180 lines

  1. /*
  2.  * Generic Convex Polygon Scan Conversion and Clipping
  3.  * by Paul Heckbert
  4.  * from "Graphics Gems", Academic Press, 1990
  5.  */
  6.  
  7. /*
  8.  * poly_scan.c: point-sampled scan conversion of convex polygons
  9.  *
  10.  * Paul Heckbert    1985, Dec 1989
  11.  */
  12.  
  13. #include <stdio.h>
  14. #include <math.h>
  15. #include "poly.h"
  16.  
  17. /*
  18.  * poly_scan: Scan convert a polygon, calling pixelproc at each pixel with an
  19.  * interpolated Poly_vert structure.  Polygon can be clockwise or ccw.
  20.  * Polygon is clipped in 2-D to win, the screen space window.
  21.  *
  22.  * Scan conversion is done on the basis of Poly_vert fields sx and sy.
  23.  * These two must always be interpolated, and only they have special meaning
  24.  * to this code; any other fields are blindly interpolated regardless of
  25.  * their semantics.
  26.  *
  27.  * The pixelproc subroutine takes the arguments:
  28.  *
  29.  *    pixelproc(x, y, point)
  30.  *    int x, y;
  31.  *    Poly_vert *point;
  32.  *
  33.  * All the fields of point indicated by p->mask will be valid inside pixelproc
  34.  * except sx and sy.  If they were computed, they would have values
  35.  * sx=x+.5 and sy=y+.5, since sampling is done at pixel centers.
  36.  */
  37.  
  38. void poly_scan(p, win, pixelproc)
  39. register Poly *p;        /* polygon */
  40. Window *win;            /* 2-D screen space clipping window */
  41. void (*pixelproc)();        /* procedure called at each pixel */
  42. {
  43.     register int i, li, ri, y, ly, ry, top, rem;
  44.     register unsigned long mask;
  45.     double ymin;
  46.     Poly_vert l, r, dl, dr;
  47.  
  48.     if (p->n>POLY_NMAX) {
  49.     fprintf(stderr, "poly_scan: too many vertices: %d\n", p->n);
  50.     return;
  51.     }
  52.     if (sizeof(Poly_vert)/sizeof(double) > 32) {
  53.     fprintf(stderr, "Poly_vert structure too big; must be <=32 doubles\n");
  54.     exit(1);
  55.     }
  56.  
  57.     ymin = HUGE;
  58.     for (i=0; i<p->n; i++)        /* find top vertex (y points down) */
  59.     if (p->vert[i].sy < ymin) {
  60.         ymin = p->vert[i].sy;
  61.         top = i;
  62.     }
  63.  
  64.     li = ri = top;            /* left and right vertex indices */
  65.     rem = p->n;                /* number of vertices remaining */
  66.     y = ceil(ymin-.5);            /* current scan line */
  67.     ly = ry = y-1;            /* lower end of left & right edges */
  68.     mask = p->mask & ~POLY_MASK(sy);    /* stop interpolating screen y */
  69.  
  70.     while (rem>0) {    /* scan in y, activating new edges on left & right */
  71.             /* as scan line passes over new vertices */
  72.  
  73.     while (ly<=y && rem>0) {    /* advance left edge? */
  74.         rem--;
  75.         i = li-1;            /* step ccw down left side */
  76.         if (i<0) i = p->n-1;
  77.         incrementalize_y(&p->vert[li], &p->vert[i], &l, &dl, y, mask);
  78.         ly = floor(p->vert[i].sy+.5);
  79.         li = i;
  80.     }
  81.     while (ry<=y && rem>0) {    /* advance right edge? */
  82.         rem--;
  83.         i = ri+1;            /* step cw down right edge */
  84.         if (i>=p->n) i = 0;
  85.         incrementalize_y(&p->vert[ri], &p->vert[i], &r, &dr, y, mask);
  86.         ry = floor(p->vert[i].sy+.5);
  87.         ri = i;
  88.     }
  89.  
  90.     while (y<ly && y<ry) {        /* do scanlines till end of l or r edge */
  91.         if (y>=win->y0 && y<=win->y1)
  92.         if (l.sx<=r.sx) scanline(y, &l, &r, win, pixelproc, mask);
  93.         else        scanline(y, &r, &l, win, pixelproc, mask);
  94.         y++;
  95.         increment(&l, &dl, mask);
  96.         increment(&r, &dr, mask);
  97.     }
  98.     }
  99. }
  100.  
  101. /* scanline: output scanline by sampling polygon at Y=y+.5 */
  102.  
  103. static scanline(y, l, r, win, pixelproc, mask)
  104. int y;
  105. unsigned long mask;
  106. Poly_vert *l, *r;
  107. Window *win;
  108. void (*pixelproc)();
  109. {
  110.     int x, lx, rx;
  111.     Poly_vert p, dp;
  112.  
  113.     mask &= ~POLY_MASK(sx);        /* stop interpolating screen x */
  114.     lx = ceil(l->sx-.5);
  115.     if (lx<win->x0) lx = win->x0;
  116.     rx = floor(r->sx-.5);
  117.     if (rx>win->x1) rx = win->x1;
  118.     if (lx>rx) return;
  119.     incrementalize_x(l, r, &p, &dp, lx, mask);
  120.     for (x=lx; x<=rx; x++) {        /* scan in x, generating pixels */
  121.     (*pixelproc)(x, y, &p);
  122.     increment(&p, &dp, mask);
  123.     }
  124. }
  125.  
  126. /*
  127.  * incrementalize_y: put intersection of line Y=y+.5 with edge between points
  128.  * p1 and p2 in p, put change with respect to y in dp
  129.  */
  130.  
  131. static incrementalize_y(p1, p2, p, dp, y, mask)
  132. register double *p1, *p2, *p, *dp;
  133. register unsigned long mask;
  134. int y;
  135. {
  136.     double dy, frac;
  137.  
  138.     dy = ((Poly_vert *)p2)->sy - ((Poly_vert *)p1)->sy;
  139.     if (dy==0.) dy = 1.;
  140.     frac = y+.5 - ((Poly_vert *)p1)->sy;
  141.  
  142.     for (; mask!=0; mask>>=1, p1++, p2++, p++, dp++)
  143.     if (mask&1) {
  144.         *dp = (*p2-*p1)/dy;
  145.         *p = *p1+*dp*frac;
  146.     }
  147. }
  148.  
  149. /*
  150.  * incrementalize_x: put intersection of line X=x+.5 with edge between points
  151.  * p1 and p2 in p, put change with respect to x in dp
  152.  */
  153.  
  154. static incrementalize_x(p1, p2, p, dp, x, mask)
  155. register double *p1, *p2, *p, *dp;
  156. register unsigned long mask;
  157. int x;
  158. {
  159.     double dx, frac;
  160.  
  161.     dx = ((Poly_vert *)p2)->sx - ((Poly_vert *)p1)->sx;
  162.     if (dx==0.) dx = 1.;
  163.     frac = x+.5 - ((Poly_vert *)p1)->sx;
  164.  
  165.     for (; mask!=0; mask>>=1, p1++, p2++, p++, dp++)
  166.     if (mask&1) {
  167.         *dp = (*p2-*p1)/dx;
  168.         *p = *p1+*dp*frac;
  169.     }
  170. }
  171.  
  172. static increment(p, dp, mask)
  173. register double *p, *dp;
  174. register unsigned long mask;
  175. {
  176.     for (; mask!=0; mask>>=1, p++, dp++)
  177.     if (mask&1)
  178.         *p += *dp;
  179. }
  180.